﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

class ProtocolMessage
{
    //Lista de comandos aceita pelo protocolo
    public enum ConnectionStatus
    {
        FullRoom,
        WelcomeAboard
    }

    public struct WinInform
    {
        public WinDirection direction;
        public byte x;
        public byte y;
    }

    //Enum que informa o sentido da jogada vitoriosa
    public enum WinDirection
    {
        Lost,           //Não ganhou
        Horizontal,     //A vitoria foi na horizontal
        Vertical,       //A vitoria foi na vertical
        DiagonalToRight,//A vitoria foi na diagonal da esquerda para a direita
        DiagonalToLeft, //A vitoria foi na diagonal da direita para a esquerda
    }

    //Lista de comandos aceita pelo protocolo
    public enum Command
    {
        InsertPiece,    //Comando para inserir uma peça
        RefreshBoard,   //Comando para Atualizar o tabuleiro dos jogadores
        ItsYourTurn,    //Comando para avisar o jogador que é a vez dele de jogar
        EndOfGame,      //Fim de jogo
        IwantPlay,      //Comando enviado pelo cliente quando ele quer jogar
        ConnectionResponse,
        TextInformation, //Mensagem de texto com informações diversas
        Null,
    }

    public byte MyID;
    public byte SenderID;                   //Identificador do jogador que está mandando a mensagem
    public WinInform WinInformation;         //Possui a informação referente a jogada vitoriosa
    public Command Cmd;                     //Comando recebido
    public byte XCoordinate, YCoordinate;   //Coordenadas correspondentes ao comando recebido
    public byte[] BoardData = new byte[225]; //Bytes com as informações de preenchimento do tabuleiro
    public byte MatchResult;               //Byte com a informação do resultado da partida;
    public String TextMessage;
    public ConnectionStatus ConnStatus = ConnectionStatus.FullRoom;

    public ProtocolMessage()
    {
        SenderID = 0; ;                   //Identificador do jogador que está mandando a mensagem
        Cmd = Command.EndOfGame;                     //Comando recebido
        XCoordinate = 0;
        YCoordinate = 0;   //Coordenadas correspondentes ao comando recebido        
        MatchResult = 0;               //Byte com a informação do resultado da partida;
        TextMessage = "";
    }

    /// <summary>
    /// Converte um array de bytes em uma mensagem do protocolo customizado
    /// criado para o jogo
    /// </summary>
    /// <param name="data">Array de bytes com os dados do protocolo</param>
    public ProtocolMessage(byte[] data)
    {
        //O primeiro byte é o ID do jogador que enviou a mensagem
        this.SenderID = data[0];

        //O segundo byte é o comando enviado
        this.Cmd = (Command)data[1];

        switch (Cmd)
        {
            case Command.InsertPiece:
                //Caso o comando é para inserir uma peça, sabemos que o 3º byte
                //possui a coordenada X e o 4º a coordenada Y do tabuleiro
                this.XCoordinate = data[2];
                this.YCoordinate = data[3];
                break;
            case Command.RefreshBoard:
                //Caso o comando é para atualizar o tabuleiro, sabemos que os próximos
                //113 bytes correspondem as posições do tabuleiro, sendo que cada
                //bit corresponde a uma posição.
                for (int i = 0; i < 225; i++)
                {
                    BoardData[i] = data[i + 2];
                }
                break;
            case Command.ItsYourTurn:
                //Comando que apenas avisa ao jogador que é a vez dele de jogar

                break;
            case Command.EndOfGame:
                //Comando que avisa o jogador que o jogo acabou. Se o byte recebido for 0, ele perdeu, se for 1
                //ele venceu.
                MatchResult = data[2];
                WinInformation.direction = (WinDirection)data[3];
                WinInformation.x = data[4];
                WinInformation.y = data[5];
                break;
            case Command.IwantPlay:
                //Comando enviado pelo jogador quando ele deseja entrar em um jogo

                break;
            case Command.TextInformation:
                //Comando enviado pelo jogador quando ele deseja entrar em um jogo
                this.TextMessage = Encoding.UTF8.GetString(data, 2, data.Length - 2);
                break;

            case Command.ConnectionResponse:
                //Comando enviado pelo j/servidor para avisar ao jogador se ele pode jogar
                this.ConnStatus = (ConnectionStatus)data[2];
                this.MyID = data[3];
                break;


            default:
                break;
        }
    }

    /// <summary>
    /// Converte as propriedades da mensagem em bytes para enviar
    /// </summary>
    /// <returns>Array de bytes contendo as informações</returns>
    public byte[] ToByte()
    {
        List<byte> result = new List<byte>();

        //O primeiro byte deve ser o ID
        result.Add(MyID);

        //O segundo byte deve ser o comando
        result.Add((byte)Cmd);

        switch (Cmd)
        {
            case Command.InsertPiece:
                //Caso o comando é para inserir uma peça, sabemos que o 3º byte
                //possui a coordenada X e o 4º a coordenada Y do tabuleiro
                result.Add(XCoordinate);
                result.Add(YCoordinate);
                break;
            case Command.RefreshBoard:
                //Caso o comando é para atualizar o tabuleiro, sabemos que os próximos
                //29 bytes correspondem as posições do tabuleiro, sendo que cada
                //bit corresponde a uma posição.
                result.AddRange(BoardData);
                break;
            case Command.ItsYourTurn:
                //Comando que apenas avisa ao jogador que é a vez dele de jogar

                break;
            case Command.EndOfGame:
                //Comando que avisa o jogador que o jogo acabou. Se o byte recebido for 0, ele perdeu, se for 1
                //ele venceu.
                result.Add(MatchResult);
                result.Add((byte)WinInformation.direction);
                result.Add((byte)WinInformation.x);
                result.Add((byte)WinInformation.y);
                break;
            case Command.IwantPlay:
                //Comando enviado pelo jogador quando ele deseja entrar em um jogo

                break;
            case Command.TextInformation:
                //Comando enviado pelo jogador quando ele deseja entrar em um jogo
                result.AddRange(Encoding.UTF8.GetBytes(TextMessage));
                result.Add(0);
                break;
            case Command.ConnectionResponse:
                //Comando enviado pelo j/servidor para avisar ao jogador se ele pode jogar
                result.Add(Convert.ToByte(ConnStatus));
                result.Add(MyID);
                break;


            default:
                break;
        }
        return result.ToArray();
    }

}
